package ipc;

import ipc.State;
import ipc.Simulator;
import java.util.Random;
import java.util.ArrayList;
import ipc.StateNode;
import java.util.List;

public class ActionNode<S extends State, A> extends Node<S, A>{
        private A action_;

	public A getAction(){
		return action_;
	}

	public static int SPARSE_SMAPLE_SIZE;

        public ActionNode(A action ) {
            action_ = action;
	    children = new ArrayList<Node<S,A>>();	
        }

        @Override
        public int hashCode(){
		throw new RuntimeException("I told you  not to use hashcodes...");
        }
        /**
         * Will take an action from the current simulator's state, create a new
         * state node at the next state and return that state node. If sparse
         * sampling limit has been reach then a random node is returned from the
         * current list of children (this is faster).
         * 
         * @param simulator
         *            used to simulate actions.
         * @return selected child state node.
         */
        public Node<S, A> selectChild(Simulator<S, A> simulator, Random _rand, int depth) {
//	    System.err.println("action node ");
	    Node<S,A> ret = null;
            if (SPARSE_SMAPLE_SIZE == -1 || visits_ < SPARSE_SMAPLE_SIZE) {
		Simulator<S,A> clone = simulator.copy();
		clone.takeAction(action_);
		
		
		
		StateNode<S, A> statenode = new StateNode<S, A>(clone.getState(), clone.getLegalActions() );
		
		boolean found = false;

                for( Node<S,A> n : children ){ 
			if(n.equals(statenode)){
//				System.err.println("Found");
				found = true;
				ret = n;
				break;
			}
		}

                if(!found){
			children.add(statenode);
	                ret = statenode;
		}

            } else {
		double[] visits = new double[children.size()];
		double sum = 0;

		for(int i = 0; i < children.size(); ++i ){
			sum += children.get(i).getVisits();
			visits[i] = sum;
		}

		for( int i = 0; i < visits.length; ++i )
			visits[i] /= sum;

		double lucky = _rand.nextDouble();

		int i = 0;

		for( i = 0 ; i < visits.length; ++i ){
			if( visits[i] >= lucky )
				break;
}
		ret = children.get(i);
	}
	simulator.setState(((StateNode<S,A>)ret).getState());
	simulator.incTime();
	if(  children.size() > SPARSE_SMAPLE_SIZE ){
		throw new RuntimeException("More children than sammple size");
	}

	return ret;
     }

     public String toString(){
      	return "ACTIONNODE " + this.visits_+" " + this.rewards_+" " + this.action_.toString();
     }

     public Node<S, A> getMaxChild(){
		throw new RuntimeException("Max child for action node");
	}	

     @Override
     public Node<S,A> getChild(S state, List<A> legals) throws Exception{	
    	 for( Node<S,A> n : children ){
    		 S st  = ((StateNode<S,A>)n).getState();
    		 if( state.equals(st) ){
//    			 System.out.println("Found a thing");
    			 return n;
    		 }
    	 }
    	 
//    	 System.out.println("Unexpected state");
//    	 System.out.print("\n\nmy children are\n\n"+children);
//    	 System.out.println("\n\nYOU wanted " + state + " ");

		StateNode<S,A> st = new StateNode<S,A>(state, legals);
		children.add(st);
		return st;		
     }	

}
